/*
    This file is part of Raptor.

    Raptor is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Raptor is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Raptor.  If not, see <http://www.gnu.org/licenses/>.

 */

#include "netload_in.h"

pluginHoster::pluginHoster()
{
    action = ACTION_NONE;
    step = 0;
    multipl = 1024;
    abort = false;
    cookie = "";
    lastSize = 0;

    waitTimer.setSingleShot(false);
    waitTimer.setInterval(1000);

    speedTimer.setSingleShot(false);
    speedTimer.setInterval(this->speedIntervall);

    loadCookie();

    this->_state = STATE_STOPPED;

    this->_info.allowOtherHostnames = false;
    this->_info.free.downloads = 0;
    this->_info.free.maxDownloads = 1;
    this->_info.free.maxConnections = 1;
    this->_info.premium.downloads = 0;
    this->_info.premium.maxDownloads = 0;
    this->_info.premium.maxConnections = 0;
    this->_info.host = "netload.in";
    this->_info.name = "netload.in";
    this->_info.reHost = QRegExp("^netload\\.in$");
    this->_info.reLink = QRegExp("^(https?://)?netload\\.in(?:.*)file_id=([^&]*)(&(?:.*))?$");
    this->_info.mode = this->_mode;

    QSettings settings("raptor-loader", "Raptor");
    this->_info.maxDownloads = settings.value("hoster/netload.in/maxDownloads", "0").toInt();

    connect(&speedTimer, SIGNAL(timeout()), this, SLOT(slot_speedTimer_timeout()));
    connect(&waitTimer, SIGNAL(timeout()), this, SLOT(slot_waitTimer_timeout()));
}

pluginHoster::~pluginHoster()
{
    //qDebug() << QString("~pluginHoster no. %1").arg(this->_id);
}

QObject* pluginHoster::clone()
{
    return new pluginHoster();
}

void pluginHoster::start()
{
    this->_progress = 0;
    this->_state = STATE_RUNNING;

    step = 0;
    //emit needCaptcha(this->_id, "http://doc.trolltech.com/4.6/images/qt-logo.png", "png");
    request(this->_url, "GET", QByteArray(), QMap<QString, QString>());
}

void pluginHoster::stop()
{
    if(this->_state != STATE_STOPPED)
    {
        abort = true;
        if(reply) reply->abort();
    }
}

void pluginHoster::login(QString const& user, QString const& pass)
{
    Q_UNUSED(user);
    Q_UNUSED(pass);

    this->_mode = MODE_LOGIN;

    this->_errorStr = tr("Premium login not yet implemented.");
    setError();
}

void pluginHoster::getSize()
{
    this->_mode = MODE_GET_SIZE;

    cookie = "";

    QByteArray post;
    for(int i=0; i < this->_url.encodedQueryItems().count(); ++i)
    {
        if(i > 0)
            post.append("&" + this->_url.encodedQueryItems().at(i).first + "=" + this->_url.encodedQueryItems().at(i).second);
        else
            post.append(this->_url.encodedQueryItems().at(i).first + "=" + this->_url.encodedQueryItems().at(i).second);
    }

    request(this->_url, "GET", QByteArray(), QMap<QString, QString>());
}

bool pluginHoster::setLink(QUrl const& url)
{
    if(url.host().indexOf(this->_info.reHost) == -1)
    {
        return false;
    } else
    {
        this->_url = url;

        if(this->_url.host() != "netload.in")
        {
            this->_url.setHost("netload.in");
        }

        return true;
    }
}

//private ->

void pluginHoster::request(QUrl const& url, QString const& method, QByteArray const& post, QMap<QString, QString> const& headerData)
{
    QNetworkRequest request(url);

    QMap<QString, QString>::const_iterator it = headerData.constBegin();
    for(;it!=headerData.constEnd(); ++it)
    {
        request.setRawHeader(QUrl::toPercentEncoding(it.key()), QUrl::toPercentEncoding(it.value()));
    }

    if(method == "POST")
        reply = qnam.post(request, post);
    else
        reply = qnam.get(request);

    connect(reply, SIGNAL(finished()), this, SLOT(slot_reply_finished()));
    connect(reply, SIGNAL(readyRead()), this, SLOT(slot_reply_readyRead()));
    connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(slot_reply_downloadProgress(qint64, qint64)));
    connect(reply, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(slot_reply_sslErrors(const QList<QSslError> &)));
}

void pluginHoster::slot_reply_finished()
{
    if(abort)
    {
        if((this->_downloadFile))
            if(this->_downloadFile->isOpen())
                this->_downloadFile->close();

        //this->_errorStr = http.errorString();
        //emit deleteMe(this->_id, error);
        setError();
        return;
    }

    page = QString(response);

    switch(this->_mode)
    {
        case MODE_FREE:
            doFree();
            break;

        case MODE_PREMIUM:
            doPremium();
            break;

        case MODE_GET_SIZE:
            doGetSize();
            break;

        case MODE_LOGIN:
            doLogin();
            break;
    }
}

void pluginHoster::slot_reply_readyRead()
{
    if((this->_downloadFile) && this->_downloadFile->isOpen())
    {
         this->_downloadFile->write(reply->readAll());
    } else
    {
        response.append(reply->readAll());
    }
}

void pluginHoster::slot_reply_downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    if(this->_state == STATE_DOWNLOADING)
    {
        this->_downloaded = bytesReceived;
        this->_fileSize = bytesTotal;

        if(this->_fileSize > 0) this->_progress = (int)((double)this->_downloaded * 100.0 / (double)this->_fileSize);
    }
}

void pluginHoster::slot_reply_sslErrors(const QList<QSslError> & errors)
{
    //todo:
    Q_UNUSED(errors);
    reply->ignoreSslErrors();
}

void pluginHoster::loadCookie()
{
    QSettings settings("raptor-loader", "Raptor");

    QString enc = settings.value("hoster/netload.in/settings/enc", "").toString();

    if(enc == "")
    {
        this->_mode = MODE_FREE;
        cookie = "";
    } else
    {
        this->_mode = MODE_PREMIUM;
        cookie = QString("enc=%1").arg(enc);

        this->_info.premium.maxDownloads = settings.value("hoster/netload.in/maxDownloads", "0").toInt();
    }
}

void pluginHoster::setError()
{
    this->_state = STATE_ERROR;
    emit statusMsg(this->_logId, this->_errorStr);

    //emit deleteMe(this->_id, true);
    switch(this->_mode)
    {
        case MODE_GET_SIZE:
            emit getSizeFinished(this->_id, true);
            break;

        case MODE_LOGIN:
            emit loginFinished(this->_id, true);
            break;

        case MODE_FREE:
            emit downloadFinished(this->_id, true);
            break;

        case MODE_PREMIUM:
            emit downloadFinished(this->_id, true);
            break;
    }
}

void pluginHoster::doLogin()
{
    /*
    if(this->http.lastResponse().hasKey("Set-Cookie"))
    {
        QString tmpString = this->http.lastResponse().value("Set-Cookie");

        QStringList tmpStringList = tmpString.split(";");

        for(int i=0; i<tmpStringList.size(); ++i)
        {
            QStringList item = tmpStringList.at(i).split("=");

            if(item.size() == 2)
            {
                if(item.at(0) == "enc")
                {
                    if(item.at(1).trimmed() != "")
                    {
                        QSettings settings("raptor-loader", "Raptor");

                        settings.setValue("hoster/rapidshare.com/settings/enc", item.at(1).trimmed());
                        emit loginFinished(this->_id, false);
                    }
                }
            }
        }

        emit loginFinished(this->_id, true);
    } else
    {
        setError();
    }*/
}

void pluginHoster::doGetSize()
{
    switch(step)
    {
        default:
        case 0:
        {
            QRegExp re("<div class=\"dl_first_filename\">([^<]*)<span(?:[^>]*)>,([^<]*)(.)B</span></div>");

            if(re.indexIn(page) != -1)
            {
                emit changeName(this->_id, re.cap(1).trimmed());

                double tmpSize = re.cap(2).trimmed().toDouble();

                QStringList sizeNames = QStringList() << " " << "K" << "M" << "G" << "T" << "P";

                for(int i=0; i<sizeNames.count(); ++i)
                {
                    if(re.cap(3).trimmed() == sizeNames.at(i))
                    {
                        double tmpDbl = tmpSize;

                        for(int o=0; o<i; ++o)
                            tmpDbl = tmpDbl * multipl;

                        this->_fileSize = tmpDbl;

                        break;
                    }
                }

                emit getSizeFinished(this->_id, false);
            } else
            {
                this->_fileSize = 0;
                this->_errorStr = tr("Unkown page.");
                setError();
                return;
            }

            break;
        }
    }
}

void pluginHoster::doPremium()
{
    this->_errorStr = tr("Premium download not yet implemented.");
    setError();
}

void pluginHoster::doFree()
{
    switch(step)
    {
        default:
        case 0:
        {
            QRegExp reFree("<a class=\"whitelink\" href=\"([^\"]*)\">&raquo; continue with a free download</a>");

            if(reFree.indexIn(page) != -1)
            {
                QUrl url("http://" + this->_url.host() + "/" + reFree.cap(1));

                step = 1;
                request(url, "GET", QByteArray(), QMap<QString, QString>());
            } else
            {
                this->_errorStr = "Unknown error";
                setError();
            }

            break;
        }

        case 1:
        {
            break;
        }
    }
}

void pluginHoster::setSpeed(double const& newSpeed)
{
    if(!speedList.isEmpty() && speedList.count() == this->smooth)
    {
        speedList.removeFirst();
        speedList.append(newSpeed);
    } else
    {
        speedList.append(newSpeed);
    }

    double tmpDbl = 0;

    for(int i=0; i<speedList.size(); ++i)
    {
        tmpDbl += speedList.at(i);
    }

    if(speedList.isEmpty())
        this->_speed = 0;
    else
        this->_speed = (tmpDbl / speedList.size());

    if(this->_speed < 1) this->_speed = 0;
}

//<- private


//slots ->
void pluginHoster::slot_speedTimer_timeout()
{
    if(speedTimer.interval() > 0) setSpeed((this->_downloaded - lastSize) / ((double)speedTimer.interval() / 1000.0));

    lastSize = this->_downloaded;

    if(this->_speed > 0) this->_timeLeft = (int)((double)(this->_fileSize - this->_downloaded) / this->_speed);
}

void pluginHoster::slot_waitTimer_timeout()
{
    if(this->_state == STATE_STOPPED) return;

    --this->_timeLeft;

    if(wait > 0) this->_progress = (int)(100 * ((double)(wait - this->_timeLeft) / wait));

    if(this->_timeLeft <= 0)
    {
        waitTimer.stop();

        switch(action)
        {
            case ACTION_NONE:

                break;

            case ACTION_START:

                start();
                break;

            case ACTION_DOWNLOAD:
/*
                if(!this->_downloadDir.exists(this->_folder)) this->_downloadDir.mkdir(this->_folder);

                this->_downloadDir.cd(this->_folder);

                while(this->_downloadDir.exists(this->_file))
                {
                    emit statusMsg(this->_logId, tr("file exists, renaming."));
                    this->_file = "_" + this->_file;
                }

                this->_downloadFile = new QFile(this->_downloadDir.filePath(this->_file));
                if(!this->_downloadFile->open(QIODevice::WriteOnly))
                {
                    this->_errorStr = tr("Cant open file.");
                    setError();
                    return;
                }

                step = 2;
                this->_state = STATE_DOWNLOADING;

                emit statusMsg(this->_logId, tr("Starting download."));

                this->_progress = 0;
                this->_downloadStart = QDateTime::currentDateTime();
                this->_downloadEnd = this->_downloadStart;
                this->_downloadEnd.addSecs(-1);

                waitingId = request(this->_url, "POST", QByteArray(), QMap<QString, QString>(), this->_downloadFile);
                */
                break;
        }
    }
}

void pluginHoster::setCaptcha(QString const& captcha)
{
    qDebug() << "setCaptcha" << captcha;
}

//<- slots

Q_EXPORT_PLUGIN2(netload_in, pluginHoster);
